/**
* @Author: zou.yingbin
* @Create  : 2020/9/7 9:43
* @Modify  : 2020/9/7 9:43
 */

package main

import (
	"fmt"
)

func chrHex2Asc(c byte) byte {
	if 'A' <= c {
		c = c - 0x37
	} else {
		c = c - '0'
	}
	return c
}

func Hex2Asc(src []byte) ([]byte, error) {
	if len(src)%2 != 0 {
		return nil, fmt.Errorf("hex2asc len error, must 2 times")
	}
	pDst := make([]byte, 0)
	var a, b byte = 0, 0
	for i := 0; i < len(src)/2; i++ {
		a = chrHex2Asc(src[i*2])
		a = a << 4
		b = chrHex2Asc(src[i*2+1])
		pDst = append(pDst, a|b)
	}

	return pDst, nil
}

func MacEnCrypt(srcBuff []byte) ([]byte, error) {
	strKey := "B0FB83E39A5EBFAABE471362A58393FF"
	strIV := "D951DBE037C82325"
	key := []byte(strKey)
	pKey := key[0:16]
	tKey := key[16:]

	pMac, err := MacAnsiX99(srcBuff, []byte(strIV), pKey)
	if err != nil {
		return nil, err
	}
	pBuf, err1 := Des1Encrypt(pMac, tKey)
	if err1 != nil {
		return nil, err1
	}

	pMac, err = Des1Encrypt(pBuf, pKey)
	if err != nil {
		return nil, err
	}

	pMac, err = Hex2Asc(pMac)
	if err != nil {
		return nil, err
	}

	return pMac, err
}

func MacAnsiX99(srcBuff, iv, key []byte) ([]byte, error) {
	bcdData := make([]byte, 0)
	for b := range srcBuff {
		h := (b & 0xF0) >> 4
		if h < 0x0A {
			h += '0'
		} else {
			h += 0x37
		}
		bcdData = append(bcdData, byte(h))
		l := b & 0xF0
		if l < 0x0A {
			l += '0'
		} else {
			l += 0x37
		}
		bcdData = append(bcdData, byte(l))
	}

	pMac := iv[0:]
	for i := 0; i < len(bcdData)/16; i++ {
		nPos := i * 16
		pBuf, err := BcdXor(pMac, bcdData[nPos:nPos+16])
		if err != nil {
			return nil, err
		}

		pMac, err = Des1Encrypt(pBuf, key)
		if err != nil {
			return nil, err
		}
	}

	if len(bcdData)%16 != 0 {
		pTmp := bcdData[len(bcdData)-len(bcdData)%16:]
		pBuf, err := BcdXor(pMac, pTmp)
		if err != nil {
			return nil, err
		}
		pMac, err = Des1Encrypt(pBuf, key)
		if err != nil {
			return nil, err
		}
	}

	return pMac[0:16], nil
}

func BcdXor(iv, bcd []byte) ([]byte, error) {
	if len(bcd) == 0 {
		return nil, fmt.Errorf("BcdXor len error")
	}

	nLen := len(bcd)
	buf := make([]byte, 0)
	for i := 0; i < nLen; i++ {
		a := XorChr(iv[i])
		b := XorChr(bcd[i])
		d := a ^ b
		if d > 0x09 {
			d = 0x40 + (d - 0x09)
		} else {
			d = d + 0x30
		}

		buf = append(buf, d)
	}

	return buf, nil
}

func XorChr(c byte) byte {
	if 'A' <= c && 'F' >= c {
		c = c - (0x40 - 0x09)
	} else if 'a' <= c && 'f' >= c {
		c = c - (0x60 - 0x09)
	} else {
		c = c - 0x30
	}

	return c
}

func Des1Encrypt(srcBuff, key []byte) ([]byte, error) {
	bKey, err := asc2bcd(key)
	if err != nil {
		return nil, err
	}

	bIDat, err1 := asc2bcd(srcBuff)
	if err1 != nil {
		return nil, err1
	}
	bIDat2 := make([]byte, 32)
	bKey2 := make([]byte, 32)
	copy(bIDat2, bIDat)
	copy(bKey2, bKey)
	bODat := desBaseEncrypt(bIDat2, bKey2)
	return bcd2asc(bODat)
}

func asc2bcd(srcBuff []byte) ([]byte, error) {
	len := len(srcBuff)
	if len%2 != 0 {
		return nil, fmt.Errorf("asc2bcd len error")
	}
	pDst := make([]byte, 0)
	var ch byte
	for i := 0; i < len/2; i++ {
		if 'A' <= srcBuff[2*i] {
			ch = (srcBuff[2*i] - 0x37) << 4
		} else {
			ch = (srcBuff[2*i] - '0') << 4
		}

		if 'A' <= srcBuff[2*i+1] {
			ch |= srcBuff[2*i+1] - 0x37
		} else {
			ch |= srcBuff[2*i+1] - '0'
		}
		pDst = append(pDst, ch)
	}

	return pDst, nil
}

func bcd2asc(bcd []byte) ([]byte, error) {
	len := len(bcd)
	if len%2 != 0 {
		return nil, fmt.Errorf("bcd2asc len error")
	}
	asc := make([]byte, 0)
	var c byte
	for i := 0; i < len; i++ {
		c = bcd[i] / 16
		if 0x0a > c {
			asc = append(asc, c+'0')
		} else {
			asc = append(asc, c+0x37)
		}

		c = bcd[i] % 16
		if 0x0a > c {
			asc = append(asc, c+'0')
		} else {
			asc = append(asc, c+0x37)
		}
	}

	return asc, nil
}

func desBaseEncrypt(iDat, key []byte) []byte {
	var k [17][48]byte = [17][48]byte{}
	tmp := desExpand(key)
	desSetKey(k, tmp)
	return desEncrypt(iDat, k)
}

func desExpand(src []byte) []byte {
	pDst := make([]byte, 0)
	for i := 0; i < 8; i++ {
		c := src[i]
		pDst = append(pDst, (c>>7)&1)
		pDst = append(pDst, (c>>6)&1)
		pDst = append(pDst, (c>>5)&1)
		pDst = append(pDst, (c>>4)&1)
		pDst = append(pDst, (c>>3)&1)
		pDst = append(pDst, (c>>2)&1)
		pDst = append(pDst, (c>>1)&1)
		pDst = append(pDst, c&1)
	}

	return pDst
}

func desSetKey(K [17][48]byte, key []byte) {

	pc_1_c := []byte{57, 49, 41, 33, 25, 17, 9,
		1, 58, 50, 42, 34, 26, 18,
		10, 2, 59, 51, 43, 35, 27,
		19, 11, 3, 60, 52, 44, 36}

	pc_1_d := [28]byte{63, 55, 47, 39, 31, 23, 15,
		7, 62, 54, 46, 38, 30, 22,
		14, 6, 61, 53, 45, 37, 29,
		21, 13, 5, 28, 20, 12, 4}
	ls_count := [16]byte{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}

	var CCC, D [17][28]byte
	for i := 0; i < 28; i++ {
		CCC[0][i] = key[pc_1_c[i]-1]
		D[0][i] = key[pc_1_d[i]-1]
	}

	for j := 0; j < 16; j++ {
		desLs(CCC[j+1], CCC[j], int(ls_count[j]))
		desLs(D[j+1], D[j], int(ls_count[j]))
		desSon(K[j+1], CCC[j+1], D[j+1])
	}
}

func desLs(dst, src [28]byte, count int) {
	for i := 0; i < 7; i++ {
		dst[i] = src[(i+count)%28]
		dst[i+7] = src[(i+7+count)%28]
		dst[i+14] = src[(i+14+count)%28]
		dst[i+21] = src[(i+21+count)%28]
	}
}

func desSon(k [48]byte, cc, d [28]byte) {

	pc2 := [48]byte{
		14, 17, 11, 24, 1, 5, 3, 28,
		15, 6, 21, 10, 23, 19, 12, 4,
		26, 8, 16, 7, 27, 20, 13, 2,
		41, 52, 31, 37, 47, 55, 30, 40,
		51, 45, 33, 48, 44, 49, 39, 56,
		34, 53, 46, 42, 50, 36, 29, 32}

	buf := cc[0:28]
	buf = append(buf, d[0:28]...)
	for i := 0; i < 8; i++ {
		k[i] = buf[pc2[i]-1]
		k[i+8] = buf[pc2[i+8]-1]
		k[i+16] = buf[pc2[i+16]-1]
		k[i+24] = buf[pc2[i+24]-1]
		k[i+32] = buf[pc2[i+32]-1]
		k[i+40] = buf[pc2[i+40]-1]
	}
}

func desEncrypt(pln []byte, K [17][48]byte) []byte {
	l := make([]byte, 64)
	r := make([]byte, 64)
	L := make([]byte, 64)
	R := make([]byte, 64)
	tmp := make([]byte, 64)

	desIp(l, r, pln)

	for i := 1; i < 9; i++ {
		desF(L, R, l, r, K, 2*i-1)
		copy(l, r)
		copy(r, R)
		desF(L, R, l, r, K, 2*i)
		copy(l, r)
		copy(r, R)
	}

	desIp(tmp, r, l)
	var dst [64]byte = [64]byte{}
	copy(dst[0:64], tmp)
	return desCompress(dst)
}

func desIp(l, r, txt []byte) {
	buf := desExpand(txt)

	ip_tab := [64]byte{
		58, 50, 42, 34, 26, 18, 10, 2,
		60, 52, 44, 36, 28, 20, 12, 4,
		62, 54, 46, 38, 30, 22, 14, 6,
		64, 56, 48, 40, 32, 24, 16, 8,
		57, 49, 41, 33, 25, 17, 9, 1,
		59, 51, 43, 35, 27, 19, 11, 3,
		61, 53, 45, 37, 29, 21, 13, 5,
		63, 55, 47, 39, 31, 23, 15, 7}

	for i := 0; i < 8; i++ {
		l[i] = buf[ip_tab[i]-1]
		r[i] = buf[ip_tab[i+32]-1]

		l[i+8] = buf[ip_tab[i+8]-1]
		r[i+8] = buf[ip_tab[i+8+32]-1]

		l[i+16] = buf[ip_tab[i+16]-1]
		r[i+16] = buf[ip_tab[i+16+32]-1]

		l[i+24] = buf[ip_tab[i+24]-1]
		r[i+24] = buf[ip_tab[i+24+32]-1]
	}
}

func desF(L, R, l, r []byte, K [17][48]byte, n int) {
	var i, j, y, z int = 0, 0, 0, 0
	var c byte
	var buf [64]byte = [64]byte{}

	e_r := [48]byte{
		31, 0, 1, 2, 3, 4, 3, 4,
		5, 6, 7, 8, 7, 8, 9, 10,
		11, 12, 11, 12, 13, 14, 15, 16,
		15, 16, 17, 18, 19, 20, 19, 20,
		21, 22, 23, 24, 23, 24, 25, 26,
		27, 28, 27, 28, 29, 30, 31, 0}

	tmp := []byte{
		14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
		0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
		4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
		15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,

		15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
		3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
		0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
		13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,

		10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
		13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
		13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
		1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,

		7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
		13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
		10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
		3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,

		2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
		14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
		4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
		11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,

		12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
		10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
		9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
		4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,

		4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
		13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
		1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
		6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,

		13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
		1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
		7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
		2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}

	var SSS [8][4][16]byte = [8][4][16]byte{}

	// 初始化.
	{
		var nIndex int = 0
		for i := 0; i < 8; i++ {
			for j := 0; j < 4; j++ {
				for k := 0; k < 16; k++ {
					SSS[i][j][k] = tmp[nIndex]
					nIndex++
				}
			}
		}
	}

	for i = 0; i < 8; i++ {
		j = 6 * i

		y = int((r[e_r[j]] ^ K[n][j]) << 1)
		y |= int(r[e_r[j+5]] ^ K[n][j+5])

		z = int((r[e_r[j+1]] ^ K[n][j+1]) << 3)
		z |= int((r[e_r[j+2]] ^ K[n][j+2]) << 2)
		z |= int((r[e_r[j+3]] ^ K[n][j+3]) << 1)
		z |= int(r[e_r[j+4]] ^ K[n][j+4])

		c = SSS[i][y][z]

		buf[4*i] = (((c) & 1) << 24) |
			(((c >> 1) & 1) << 16) |
			(((c >> 2) & 1) << 8) |
			((c >> 3) & 1)

	}

	P := [32]byte{
		15, 6, 19, 20, 28, 11, 27, 16,
		0, 14, 22, 25, 4, 17, 30, 9,
		1, 7, 23, 13, 31, 26, 2, 8,
		18, 12, 29, 5, 21, 10, 3, 24}

	for i = 0; i < 8; i++ {
		j = i << 2

		R[j] = ((buf[P[j+3]] ^ l[j+3]) << 24) |
			((buf[P[j+2]] ^ l[j+2]) << 16) |
			((buf[P[j+1]] ^ l[j+1]) << 8) |
			(buf[P[j]] ^ l[j])
	}
}

func desCompress(src [64]byte) []byte {
	var c byte = 0
	pDst := make([]byte, 0)
	for i := 0; i < 8; i++ {
		c = src[i*8] << 7
		c += src[i*8+1] << 6
		c += src[i*8+2] << 5
		c += src[i*8+3] << 4
		c += src[i*8+4] << 3
		c += src[i*8+5] << 2
		c += src[i*8+6] << 1
		c += src[i*8+7]
		pDst = append(pDst, c)
	}

	return pDst
}
